
import java.awt.BorderLayout;
import java.lang.Math;
import javax.media.opengl.DebugGL;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;
import javax.swing.JFrame;

import com.sun.opengl.util.FPSAnimator;
import org.OpenNI.*;
import java.util.Vector;

/**
 * A minimal JOGL demo.
 * 
 * @author <a href="mailto:kain@land-of-kain.de">Kai Ruhl</a>
 * @since 26 Feb 2009
 */
public class MyJoglCanvas extends GLCanvas implements GLEventListener {

	public volatile Vector<skeleton> userList;

    /** Serial version UID. */
    private static final long serialVersionUID = 1L;
    private float sploc = -1000.0f;
    private float scale = 0.1f;
    float[][] top;
    float[][] bot;
    private final float radius = 2.378f;
    private final int LineD = 100;
    

    /** The GL unit (helper class). */
    private GLU glu;

    /** The frames per second setting. */
    private int fps = 60;

    /** The OpenGL animator. */
    private FPSAnimator animator;

    /**
     * A new mini starter.
     * 
     * @param capabilities The GL capabilities.
     * @param width The window width.
     * @param height The window height.
     */
    public MyJoglCanvas(GLCapabilities capabilities, int width, int height) {
    	top = new float[LineD][3];
    	bot = new float[LineD][3];
    	double theta = 2*Math.PI/LineD;
       	
    	for (int i =0;i<LineD;i++){
    		
    		top[i][0] = (float) ((Math.cos(theta*i))*radius);
    		top[i][1] = (float) ((Math.sin(theta*i))*radius);
    		top[i][2] = 0.0f;

    		bot[i][0] = (float) ((Math.cos(theta*i))*radius);
    		bot[i][1] = (float) ((Math.sin(theta*i))*radius);
    		bot[i][2] = 0.0f;

    	}

    	
    	userList = new Vector<skeleton>(); 
    	addGLEventListener(this);
    }

    /**
     * @return Some standard GL capabilities (with alpha).
     */
    public static GLCapabilities createGLCapabilities() {
        GLCapabilities capabilities = new GLCapabilities();
        capabilities.setRedBits(8);
        capabilities.setBlueBits(8);
        capabilities.setGreenBits(8);
        capabilities.setAlphaBits(8);
        return capabilities;
    }

    /**
     * Sets up the screen.
     * 
     * @see javax.media.opengl.GLEventListener#init(javax.media.opengl.GLAutoDrawable)
     */
    public void init(GLAutoDrawable drawable) {
        drawable.setGL(new DebugGL(drawable.getGL()));
        final GL gl = drawable.getGL();

        // Enable z- (depth) buffer for hidden surface removal. 
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);

        // Enable smooth shading.
        gl.glShadeModel(GL.GL_SMOOTH);

        // Define "clear" color.
        gl.glClearColor(0f, 0f, 0f, 0f);

        // We want a nice perspective.
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);

        // Create GLU.
        glu = new GLU();

        // Start animator.
        animator = new FPSAnimator(this, fps);
        animator.start();
    }

    /**
     * The only method that you should implement by yourself.
     * 
     * @see javax.media.opengl.GLEventListener#display(javax.media.opengl.GLAutoDrawable)
     */
    public void display(GLAutoDrawable drawable) {
        if (!animator.isAnimating()) {
            return;
        }
        final GL gl = drawable.getGL();

        // Clear screen.
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        // Set camera.
        setCamera(gl, glu, 10);

        // Prepare light parameters.
        float SHINE_ALL_DIRECTIONS = 1;
        float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS};
        float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
        float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};

        // Set light parameters.
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPos, 0);
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightColorAmbient, 0);
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightColorSpecular, 0);

        // Enable lighting in GL.
        gl.glEnable(GL.GL_LIGHT1);
        gl.glEnable(GL.GL_LIGHTING);

        // Set material properties.
        float[] rgba = {0.3f, 0.5f, 1f};
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
        gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);

        // Draw sphere (possible styles: FILL, LINE, POINT).
        GLUquadric earth = glu.gluNewQuadric();
        glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
        glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
        glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
        
        final int slices = 16;
        final int stacks = 16;
 
        int count = userList.size();
        
        String[] str = {"Head", "Neck", 
        				"Left shoulder","Left elbow","Left hand",
        				"Right shoulder","Right elbow","Right hand",
        				"Torso",
        				"Left Hip","Left Knee","Left Foot",
        				"Right Hip","Right Knee","Right Foot",        				
        				}; 
        
        if (count > 0)
        {
        	for(int i=0; i<count;i++){
        		
        		skeleton localskel = userList.elementAt(i);
        		
        		
        		for(int j=0;j<15;j++){        			
        	        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
        	        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
        	        gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);

        			Point3D pt = localskel.list.elementAt(j);     				
    				gl.glPushMatrix();
        			gl.glTranslatef(pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ());
        	        glu.gluSphere(earth, radius, slices, stacks);
            		gl.glPopMatrix();
            		        			
        			if (j == skeleton.SKEL_LEFT_ELBOW)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_SHOULDER);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}
        			
        			if (j == skeleton.SKEL_RIGHT_ELBOW)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_SHOULDER);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_RIGHT_HAND)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_ELBOW);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}
        			
        			if (j == skeleton.SKEL_LEFT_HAND)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_ELBOW);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_RIGHT_HAND)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_ELBOW);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}
        			
        			if (j == skeleton.SKEL_LEFT_SHOULDER)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_HIP);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}
        			if (j == skeleton.SKEL_LEFT_SHOULDER)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_SHOULDER);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}
        			if (j == skeleton.SKEL_LEFT_HIP)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_HIP);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_RIGHT_SHOULDER)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_HIP);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_RIGHT_KNEE)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_HIP);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_RIGHT_FOOT)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_RIGHT_KNEE);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_LEFT_KNEE)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_HIP);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			if (j == skeleton.SKEL_LEFT_FOOT)
        			{
            			Point3D p2 = localskel.list.elementAt(skeleton.SKEL_LEFT_KNEE);     				
	            		float[] topPt = {pt.getX()*scale,pt.getY()*-scale,-scale*pt.getZ()};
	            		float[] botPt = {p2.getX()*scale,p2.getY()*-scale,-scale*p2.getZ()};	
	            		drawCylinder(topPt,botPt,gl);
        			}

        			
        		}
        		
                glu.gluDeleteQuadric(earth);
                sploc++;

        	}      	
        }
    }

    private void drawCylinder(float[] topPt, float[] botPt, GL gl){
    	
    	float[] rgba ={1.0f,0.0f,0.0f};
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
        gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);

        gl.glBegin(gl.GL_LINES);   	 
    	for(int i=0;i<LineD;i++)
    	{
    		int j = (i+3)%LineD;
    		gl.glVertex3f(top[i][0]+topPt[0],top[i][1]+topPt[1],top[i][2]+topPt[2]);
    		gl.glVertex3f(bot[j][0]+botPt[0],bot[j][1]+botPt[1],bot[j][2]+botPt[2]);    		
    	}
    	gl.glEnd();
    }
    
    /**
     * Resizes the screen.
     * 
     * @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable,
     *      int, int, int, int)
     */
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        final GL gl = drawable.getGL();
        gl.glViewport(0, 0, width, height);
    }

    /**
     * Changing devices is not supported.
     * 
     * @see javax.media.opengl.GLEventListener#displayChanged(javax.media.opengl.GLAutoDrawable,
     *      boolean, boolean)
     */
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
        throw new UnsupportedOperationException("Changing display is not supported.");
    }

    /**
     * @param gl The GL context.
     * @param glu The GL unit.
     * @param distance The distance from the screen.
     */
    private void setCamera(GL gl, GLU glu, float distance) {
        // Change to projection matrix.
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();

        // Perspective.
        float widthHeightRatio = (float) getWidth() / (float) getHeight();
        glu.gluPerspective(45, widthHeightRatio, 1, 1000);
        glu.gluLookAt(0, 0, -100, 0, 0, -500, 0, 1, 0);

        // Change back to model view matrix.
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
//        gl.glTranslatef(0.0f,0.0f,-100.f);
    }

    /**
     * Starts the JOGL mini demo.
     * 
     * @param args Command line args.
     */
    public final static void main(String[] args) {
        GLCapabilities capabilities = createGLCapabilities();
        MyJoglCanvas canvas = new MyJoglCanvas(capabilities, 800, 500);
        JFrame frame = new JFrame("Mini JOGL Demo (breed)");
        frame.getContentPane().add(canvas, BorderLayout.CENTER);
        frame.setSize(800, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        canvas.requestFocus();
    }

}
